var Class = {
    create: function(){
        return function(){
            this.initialize.apply(this, arguments);
        }
    }
};

var DataModel = {
    debug: true,
	log : function(action, object, value, result) {
		var message =  "action : " + action;
			message += "\n [object : '" + object +"'";
			if (value != undefined)
				message += "\n  value  : '" + value +"'";
			message += "\n  result  : '" + result +"'";
			message += " ]";
		alert(message);
	},
	_version: {
        read: true,
        write: false,
        vocabulary: null,
        value: null,
        init_value: null,
        validation: ["write"]
    },
    completion_status: {
        read: true,
        write: true,
        vocabulary: ["unknown", "completed", "not attempted", "incomplete"],
        value: null,
        init_value: null,
        validation: ["vocabulary"]
    },
    completion_threshold: {
        read: true,
        write: false,
        min: "0.0",
        max: "1.0",
        vocabulary: null,
        value: null,
        init_value: null,
        validation: ["write", "min", "max"]
    },
    credit: {
        read: true,
        write: false,
        vocabulary: ["credit", "no-credit"],
        value: null,
        init_value: null,
        validation: ["write", "vocabulary"]
    },
    entry: {
        read: true,
        write: false,
        vocabulary: ["ab-initio", "resume", ""],
        value: null,
        init_value: null,
        validation: ["write"]
    },
    exit: {
        read: false,
        write: true,
        vocabulary: ["time-out", "suspend", "logout", "normal", ""],
        value: null,
        init_value: null,
        validation: ["read"]
    },
    launch_data: {
        read: true,
        write: false,
        range: "4000",
        vocabulary: null,
        value: null,
        init_value: null,
        validation: ["write", "range"]
    },
    learner_id: {
        read: true,
        write: false,
        uri: "4000",
        vocabulary: null,
        value: null,
        init_value: null,
        validation: ["write", "uri"]
    },
    learner_name: {
        read: true,
        write: false,
        range: "250",
        langString: "250",
        vocabulary: null,
        value: null,
        init_value: null,
        validation: ["write", "range", "langString"]
    },
    location: {
        read: true,
        write: true,
        range: "1000",
        vocabulary: null,
        value: null,
        init_value: null,
        validation: ["range"]
    },
    max_time_allowed: {
        read: true,
        write: false,
        duration: true,
        vocabulary: null,
        value: null,
        init_value: null,
        validation: ["write", ]
    },
    mode: {
        read: true,
        write: false,
        vocabulary: ["browse", "normal", "review"],
        value: null,
        init_value: null,
        validation: ["write", "vocabulary"]
    },
    progress_measure: {
        read: true,
        write: true,
        min: "0.0",
        max: "1.0",
        vocabulary: null,
        value: null,
        init_value: null,
        validation: ["min", "max"]
    },
    scaled_passing_score: {
        read: true,
        write: false,
        min: "-1.0",
        max: "1.0",
        vocabulary: null,
        value: null,
        init_value: null,
        validation: ["write", "min", "max"]
    },
    session_time: {
        read: false,
        write: true,
        duration: true,
        vocabulary: null,
        value: null,
        init_value: null,
        validation: ["read"]
    },
    success_status: {
        read: true,
        write: true,
        vocabulary: ["passed", "failed", "unknown"],
        value: null,
        init_value: null,
        validation: ["vocabulary"]
    },
    suspend_data: {
        read: true,
        write: true,
        range: "4000",
        vocabulary: null,
        value: null,
        init_value: null,
        validation: ["range"]
    },
    time_limit_action: {
        read: true,
        write: false,
        vocabulary: ["exit,message", "continue,message", "exit,no message", "continue,no message"],
        value: null,
        init_value: null,
        validation: ["write", "vocabulary"]
    },
    total_time: {
        read: true,
        write: false,
        duration: true,
        vocabulary: null,
        value: null,
        init_value: null,
        validation: ["write"]
    },
    get: function(object){
        return eval("this." + object + ".value");
    },
    set: function(object, value){
        var temp = (eval("this." + object));
        temp.value = value;
        return true;
    }
};

DataModel.error = {
    lastError: {
        errorCode: "0",
        errorString: "No Error",
        diagnostic: "No Error"
    },
    code_0: {
        errorCode: "0",
        errorString: "No Error",
        diagnostic: "No Error"
    },
    code_101: {
        errorCode: "101",
        errorString: "General Exception",
        diagnostic: "General Exception"
    },
    code_102: {
        errorCode: "102",
        errorString: "General Initialization Error",
        diagnostic: "General Initialization Error"
    },
    code_103: {
        errorCode: "103",
        errorString: "Already Initialized",
        diagnostic: "Already Initialized"
    },
    code_104: {
        errorCode: "104",
        errorString: "Content Instance Terminated",
        diagnostic: "Content Instance Terminated"
    },
    code_111: {
        errorCode: "111",
        errorString: "General Termination Failure",
        diagnostic: "General Termination Failure"
    },
    code_112: {
        errorCode: "112",
        errorString: "Termination Before Initialization",
        diagnostic: "Termination Before Initialization"
    },
    code_113: {
        errorCode: "113",
        errorString: "Termination After Termination",
        diagnostic: "Termination After Termination"
    },
    code_122: {
        errorCode: "122",
        errorString: "Retrieve Data Before Initialization",
        diagnostic: "Retrieve Data Before Initialization"
    },
    code_123: {
        errorCode: "123",
        errorString: "Retrieve Data After Termination",
        diagnostic: "Retrieve Data After Termination"
    },
    code_132: {
        errorCode: "132",
        errorString: "Store Data Before Initialization",
        diagnostic: "Store Data Before Initialization"
    },
    code_133: {
        errorCode: "133",
        errorString: "Store Data After Termination",
        diagnostic: "Store Data After Termination"
    },
    code_142: {
        errorCode: "142",
        errorString: "Commit Before Initialization",
        diagnostic: "Commit Before Initialization"
    },
    code_143: {
        errorCode: "143",
        errorString: "Commit After Termination",
        diagnostic: "Commit After Termination"
    },
    code_201: {
        errorCode: "201",
        errorString: "General Argument Error",
        diagnostic: "General Argument Error"
    },
    code_301: {
        errorCode: "301",
        errorString: "General Get Failure",
        diagnostic: "General Get Failure"
    },
    code_351: {
        errorCode: "351",
        errorString: "General Set Failure",
        diagnostic: "General Set Failure"
    },
    code_391: {
        errorCode: "391",
        errorString: "General Commit Failure",
        diagnostic: "General Commit Failure"
    },
    code_401: {
        errorCode: "401",
        errorString: "Undefined Data Model Element",
        diagnostic: "Undefined Data Model Element"
    },
    code_402: {
        errorCode: "402",
        errorString: "Unimplemented Data Model Element",
        diagnostic: "Unimplemented Data Model Element"
    },
    code_403: {
        errorCode: "403",
        errorString: "Data Model Element Value Not Initialized",
        diagnostic: "Data Model Element Value Not Initialized"
    },
    code_404: {
        errorCode: "404",
        errorString: "Data Model Element Is Read Only",
        diagnostic: "Data Model Element Is Read Only"
    },
    code_405: {
        errorCode: "405",
        errorString: "Data Model Element Is Write Only",
        diagnostic: "Data Model Element Is Write Only"
    },
    code_406: {
        errorCode: "406",
        errorString: "Data Model Element Type Mismatch",
        diagnostic: "Data Model Element Type Mismatch"
    },
    code_407: {
        errorCode: "407",
        errorString: "Data Model Element Value Out Of Range",
        diagnostic: "Data Model Element Value Out Of Range"
    },
    code_408: {
        errorCode: "408",
        errorString: "Data Model Dependency Not Established",
        diagnostic: "Data Model Dependency Not Established"
    },
    code_301: {
        errorCode: "301",
        errorString: "General Get Failure",
        diagnostic: "Data Model Element does not have Children"
    },
    code_301: {
        errorCode: "301",
        errorString: "General Get Failure",
        diagnostic: "Data Model Element does not have Count"
    },
    code_301: {
        errorCode: "301",
        errorString: "General Get Failure",
        diagnostic: "Data Model Element does not have Version"
    },
    code_351: {
        errorCode: "351",
        errorString: "General Set Failure",
        diagnostic: "Data Model Array Set out of Order"
    },
    code_301: {
        errorCode: "301",
        errorString: "General Get Failure",
        diagnostic: "Value Out of Range"
    },
    code_351: {
        errorCode: "351",
        errorString: "General Get Failure",
        diagnostic: "No Element Specified"
    },
    code_351: {
        errorCode: "351",
        errorString: "General Set Failure",
        diagnostic: "Value is not Unique"
    },
    code_351: {
        errorCode: "351",
        errorString: "General Set Failure",
        diagnostic: "Error - Maximum Exceeded"
    },
    code_404: {
        errorCode: "404",
        errorString: "Data Model Element Is Read Only",
        diagnostic: "Data Model Element Is a Keyword"
    },
    code_401: {
        errorCode: "401",
        errorString: "Undefined Data Model Element",
        diagnostic: "Request was Invalid"
    },
    code_301: {
        errorCode: "301",
        errorString: "General Get Failure",
        diagnostic: "Invalid Argument Error"
    },
    
    getErrorCode: function(code){
        return (eval("this.code_" + code + ".errorCode"));
    },
    getErrorString: function(code){
        return (eval("this.code_" + code + ".errorString"));
    },
    getDiagnostic: function(code){
        return (eval("this.code_" + code + ".diagnostic"));
    },
    getErrorObject: function(code){
        return (eval("this.code_" + code));
    },
    setCurrentError: function(code){
        this.currentError = this.getErrorObject(code);
    },
    getCurrentCode: function(){
        return this.currentCode.errorCode;
    },
    getCurrentErrorString: function(){
        return this.currentCode.errorString;
    },
    getCurrentDiagnostic: function(){
        return this.currentCode.diagnostic;
    },
    getCurrentErrorObject: function(code){
        return this.currnetError;
    }
};

DataModel.navModel = {
    vocabulary: ["continue", "previous", "choice", "exit", "exitAll", "abandon", "abandonAll", "_none_", "suspendAll"],
    isVocabulary: function(nav){
        if (this.vocabulary.include(nav)) 
            return true;
        else 
            return false;
    },
    getVocabularys: function(object){
        return this.vocabulary;
    }
};

DataModel.validation = {
    getValidate : ["read"],
	setValidate : ["write", "min", "max", "range", "uri", "vocaburay"],
    vocabulary: function(object, value){
		var vocabularys = eval(object + ".vocabulary");
        if (vocabularys.include(value)) 
            return "0";
        else 
            return "406";
    },
    min: function(object, value){
		var isNumber = this.isNumber(value);
		if (isNumber != "0")
			return isNumber;
		var minValue = eval(object + ".min");
        // mix null check
        if (minValue == null) 
            return "403";
        
        if (minValue <= value) 
            return "0";
        else 
            return "407";
    },
    max: function(object, value){
		var isNumber = this.isNumber(value);
		if (isNumber != "0")
			return isNumber;
		var maxValue = eval(object + ".max");
        if (maxValue == null) 
            return "403";
        
        if (maxValue >= value) 
            return "0";
        else 
            return "407";
    },
    range: function(object, value){
		var rangeValue = eval(object + ".range");
        if (rangeValue == null) 
            return "9001";
			
		return (value.replace(/\{lang=([a-z]|[A-Z]|-)*\}/, "")).length  <= rangeValue ? "0" : "9002";
        
    },
    uri: function(object, value){
		var uriValue = eval(object + ".uri");
        if (uriValue == null) 
            return false;
        
        if (value.replace(" ", "") == "" || value.substring(value.length - 1, value.length) == ":") 
            return false;
        else if (value.substring(0, 1) == "{") 
            return false;
        else if (value.replace(" ", "").length != value.length) 
            return false;
        else if (value.length > uriValue) 
        	return false;
        else 
        	return true;
    },
    
    isNumber: function(value){
		return (/^(\d|-)?\d*\.?\d*$/).test(value) ? "0" : "406";
    },
	
	read : function(object) {
		var read = eval(object + ".read");
		if (read) 
			return "0";
		else 
			return "405";
	},
	
	write : function (object) {
		var write = eval(object + ".write");
		if (write) 
			return "0";
		else 
			return "404";
	},
	isObject : function(object) {
		alert(object);
		var object = eval(object);
		return (eval(object) != null) ? "0" : "401"
	},
    
    check: function(object, type, value){
		var error = "0";
		object = object.replace("cmi.", "DataModel.");
		error = this.isObject(object);
		if (error == "0") {
			var validations = eval(object + ".validation");
			for (var i = 0; i < validations.length; i++) {
				if ((type == "get" && this.getValidate.include(validations[i])) ||
					(type == "set" && this.setValidate.include(validations[i]))) {
					error = eval("this." + validations[i] + "('" + object + "', '" + value + "')");
					if (DataModel.debug) 
						DataModel.log("validation " + validations[i], object, value, error);
				}
			}
		}
		if (type = "get") {
			if (error != "0") {
				return "";
			} else {
				return eval("DataModel." + object + ".get('" + object + "')");
			}
		} else if (type == "set") {
			if (error != "0") {
				return false;
			} else {
				return eval("DataModel." + object + ".set('" + object + "', '" + value + "')");
			}
		}
    }
};

DataModel.validation.check("cmi.location", "set", "ddddd");

DataModel.objectives = {
    _children: {
        read: true,
        write: false
    },
	_count : 0,
    id: {
        read: true,
        write: true,
        uri: "4000",
        unique: true,
        value: []
    },
    success_status: {
        read: true,
        write: true,
        vocabulary: ["passed", "failed", "unknown"],
        dependent: true,
        init_value: null,
        value: []
    },
    completion_status: {
        read: true,
        write: true,
        vocabulary: ["completed", "incomplete", "not attempted", "unknown"],
        dependent: true,
        init_value: null,
        value: []
    },
    progress_measure: {
        read: true,
        write: true,
        min: "0.0",
        max: "1.0",
        dependent: true,
        init_value: null,
        value: []
    },
    description: {
        read: true,
        write: true,
        range: "250",
        langString: "250",
        dependent: true,
        init_value: null,
        value: []
    },
    score: {
        scaled: {
            read: true,
            write: true,
            min: "-1.0",
            max: "1.0",
            dependent: true,
            init_value: null,
            value: []
        },
        raw: {
            read: true,
            write: true,
            min: null,
            max: null,
            dependent: true,
            init_value: null,
            value: []
        },
        min: {
            read: true,
            write: true,
            min: null,
            max: null,
            dependent: true,
            init_value: null,
            value: []
        },
        max: {
            read: true,
            write: true,
            min: null,
            max: null,
            dependent: true,
            init_value: null,
            value: []
        }
    },
    
    get: function(object, index){
        if (eval("this." + object + ".value.length") < index) 
            return false;
        else 
            return eval("this." + object + ".value[" + index + "]");
    },
    
    set: function(object, value, index){
        if (eval("this." + object + ".value.length") < index) 
            return false;
        var temp = (eval("this." + object));
        temp.value[index] = value;
        return true;
    }
}


DataModel.interactions = {
    _children: {
        read: true,
        write: false
    },
    id: {
        read: true,
        write: true,
        uri: "4000",
        unique: true,
        value: []
    },
    type: {
        read: true,
        write: true,
        dependent: true,
        vocabulary: ["true-false", "choice", "fill-in", "long-fill-in", "matching", "performance", "sequencing", "likert", "numeric", "other"],
        unique: true,
        value: []
    },
    timestamp: {
        read: true,
        write: true,
        dateTime: true,
        unique: true,
        value: []
    },
    weighting: {
        read: true,
        write: true,
        min: null,
        max: null,
        dateTime: true,
        value: []
    },
    learner_response: {
        read: true,
        write: true,
        type: true,
        dependent: true,
        value: []
    },
    result: {
        read: true,
        write: true,
        type: true,
        dependent: true,
        vocabulary: ["correct", "incorrect", "unanticipated", "neutral"],
        value: []
    },
    latency: {
        read: true,
        write: true,
        duration: true,
        dependent: true,
        value: []
    },
    description: {
        read: true,
        write: true,
        range: "250",
        langString: "250",
        dependent: true,
        value: []
    },
    correct_responses: null,
    objectives: null,
    
    get: function(object, index){
        if (eval("this." + object + ".value.length") < index) 
            return false;
        else 
            return eval("this." + object + ".value[" + index + "]");
    },
    
    set: function(object, value, index){
        if (eval("this." + object + ".value.length") < index) 
            return false;
        var temp = (eval("this." + object));
        temp.value[index] = value;
        return true;
    }
}

DataModel.comments_from_learner = {
    _children: {
        read: true,
        write: false
    },
    commnet: {
        read: true,
        write: true,
        value: []
    },
    location: {
        read: true,
        write: true,
        value: []
    },
    timeStamp: {
        read: true,
        write: true,
        value: []
    },
    
    getComment: function(index){
        return this.comment.value[index];
    },
    getLocation: function(index){
        return this.location.value[index];
    },
    getTimeStamp: function(index){
        return this.timeStamp.value[index];
    }
};

DataModel.comments_from_lms = {
    _children: {
        read: true,
        write: false
    },
    commnet: {
        read: true,
        write: true,
        value: []
    },
    location: {
        read: true,
        write: true,
        value: []
    },
    timeStamp: {
        read: true,
        write: true,
        value: []
    },
    
    getComment: function(index){
        return this.comment.value[index];
    },
    getLocation: function(index){
        return this.location.value[index];
    },
    getTimeStamp: function(index){
        return this.timeStamp.value[index];
    }
};







